package com.bridgeintelligent.tag.engine.mvc.service.impl;

import com.alibaba.fastjson.JSON;
import com.bridgeintelligent.tag.engine.api.IndexNameInfo;
import com.bridgeintelligent.tag.engine.core.cache.CacheConfig;
import com.bridgeintelligent.tag.engine.core.cache.CacheUtils;
import com.bridgeintelligent.tag.engine.es.base.ESQueryUtils;
import com.bridgeintelligent.tag.engine.mvc.service.IGroupService;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.MultiSearchRequest;
import org.elasticsearch.action.search.MultiSearchResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;

import java.io.IOException;

import static org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval.MONTH;
import static org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval.YEAR;

/**
 * @description
 * @author: grp 2020-10-26 14:59
 **/
@Service
@Slf4j
public class GroupServiceImpl implements IGroupService {

    @Override
    public Double getNumberInterval(String dimIdColumn, QueryBuilder queryBuilder,String indexId) throws IOException {
        Limit limit = getLimits(dimIdColumn, queryBuilder,indexId);
        if (StringUtils.isBlank(limit.getMin()) || StringUtils.isBlank(limit.getMax())) {
            return null;
        }
        return getSplit(Double.parseDouble(limit.getMin()), Double.parseDouble(limit.getMax()));
    }

    @Override
    public DateHistogramInterval getDateInterval(String dimIdColumn, QueryBuilder queryBuilder,String indexId) throws IOException {
        Limit limit = getLimits(dimIdColumn, queryBuilder, indexId);
        log.info("{}获取的limit:{}", dimIdColumn, JSON.toJSONString(limit));
        if (StringUtils.isBlank(limit.getMin()) || StringUtils.isBlank(limit.getMax())) {
            return null;
        }
        long millis = (DateTime.parse(limit.getMax()).getMillis() - DateTime.parse(limit.getMin()).getMillis()) / 1000;
        if (millis <= 10 * 365 * 24 * 60 * 60 && millis >= 9 * 365 * 24 * 60 * 60) {
            return YEAR;
        }
        if (millis <= 10 * 24 * 60 * 60 * 30 && millis >= 9 * 24 * 60 * 60 * 30) {
            return MONTH;
        }
        return new DateHistogramInterval(millis / (24 * 60 * 60 * 9) + "d");
    }

    private Double getSplit(Double low, Double high) {
        Double split = Math.ceil((high - low) / 10);
        if (split == 0) {
            return 1d;
        }
        int num = 0;
        while (split >= 100) {
            split = split / 10;
            num++;
        }
        return Math.ceil(split) * Math.pow(10, num);
    }

    private Limit getLimits(String dimId, QueryBuilder queryBuilder,String indexId) throws IOException {

        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, indexId);
        MultiSearchRequest request = new MultiSearchRequest();
        request.add(getSearchRequest(dimId, SortOrder.ASC, indexNameInfo, queryBuilder));
        request.add(getSearchRequest(dimId, SortOrder.DESC, indexNameInfo, queryBuilder));
        MultiSearchResponse multiSearchResponse =
                ESQueryUtils.getClient().multiSearch(request, RequestOptions.DEFAULT);
        Limit limit = Limit.builder().build();
        limit.setMin(getLimit(dimId, multiSearchResponse.getResponses()[0].getResponse()));
        limit.setMax(getLimit(dimId, multiSearchResponse.getResponses()[1].getResponse()));
        return limit;
    }

    private String getLimit(String dimId, SearchResponse response) {
        SearchHit[] hits = response.getHits().getHits();
        if (hits.length <= 0) {
            return null;
        }
        return hits[0].getSourceAsMap().get(dimId).toString();
    }

    private SearchRequest getSearchRequest(String dimId, SortOrder order, IndexNameInfo indexNameInfo,
                                           QueryBuilder queryBuilder) {

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        SortBuilder sortBuilder = SortBuilders.fieldSort(dimId).unmappedType("double").order(order);
        if (queryBuilder != null) {
            searchSourceBuilder.sort(sortBuilder).query(queryBuilder).trackTotalHits(true).size(1);
        } else {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            boolQueryBuilder.must(
                    QueryBuilders.boolQuery()
                                 .should(QueryBuilders.boolQuery().must(QueryBuilders.existsQuery(dimId))
                                 ));
            searchSourceBuilder.sort(sortBuilder).query(boolQueryBuilder).trackTotalHits(true).size(1);
        }
        return new SearchRequest(indexNameInfo.getDataDate()).source(searchSourceBuilder);
    }

    @Builder
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Limit {
        private String min;
        private String max;
    }
}
